package taper.controller.polypatch;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.math.BigDecimal;
import org.apache.log4j.Logger;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import taper.controller.TaperController;
import taper.controller.plc.MonitorProcessor;
import taper.controller.plc.TaperAdjustProcessor;
import taper.controller.plc.TaperAverage;
import util.Activity;
import util.Convertor;
import util.DateTimeUtil;
import util.ErrorMessage;
import util.PLCSend;
import util.PropertiesLoader;
import util.UnitConversion;
import db.DatabaseManager;
import db.EntityWrapper;
import db.entity.PadLife;
import db.entity.PolyResult;
import db.entity.PolyResultPK;
import db.entity.Polyfull;
import db.entity.Polynomial;
import db.entity.StationStatus;
import db.entity.TaperMap;
import db.entity.TaperValue;

public class PolyPatch {
	private static final Logger log = Logger.getLogger(PolyPatch.class);

	public void startPloy() {
		new Thread(new Runnable() {
			public void run() {
				
				while (true) {
				
				try {
					findTargetStation();
					Thread.sleep(PropertiesLoader.getPatchInterval());
				} catch (InterruptedException e) {
					log.error("PolyPatch:startPloy",e);
				}
				}
			}
		}).start();

	}
	
	//To find the next target station to output the average taper file.
	public void findTargetStation(){
		
		Iterator activeStationIterator = TaperController.activeStationMap.values().iterator();
		
		  while (activeStationIterator.hasNext()) {
			  StationStatus station = (StationStatus)activeStationIterator.next();
			  String stationName = station.getId().getName();
			  
			  Boolean isPolishing = (Boolean) MonitorProcessor.isPolishingMap.get(stationName);
			  
			  if (isPolishing) {
			  
					  DatabaseManager dm = new DatabaseManager();
					  
					  //get latest padlife info from db
					  List<PadLife> padLifeList = dm.listPadlifeByStationName(stationName, "desc", 1);
					  if(padLifeList!=null && padLifeList.size() > 0){
							  PadLife padLife = padLifeList.get(0);
							  
							  //sample padid : 2010-07-29 15:02:43.001
							  String padID = DateTimeUtil.format(padLife.getId().getStartLife(), DateTimeUtil.DEFAULT_DATE_FORMAT_NOW) + ".0" + stationName;
							  
							  Long sumElapseTime = dm.listPadElapseByPadId(padID);
							  Double totalPadLife = 0.0;
							  
							  if(sumElapseTime !=null && sumElapseTime!=0){
								   totalPadLife = Convertor.MiliSecondToHour(sumElapseTime);
							  }
							  
							  if(station.getCurrentPadId().equals("")){
								  log.info(stationName+" reset PadLife & PadId due to restart program");
								  int nextPad = (int)Math.floor(totalPadLife)+1;
								  station.setNextPadLife(nextPad);
								  station.setCurrentPadId(padID);  
							  }else{
								  
								  if(!padID.equals(station.getCurrentPadId())){
									  
									  int nextPad = (int)Math.floor(totalPadLife)+1;
									  station.setNextPadLife(nextPad);
									  station.setCurrentPadId(padID);
									  log.info(stationName+" change pad.New Pad ID:"+padID+".Next pad life:"+nextPad);
									  processPolynomial(stationName,totalPadLife.intValue(),padLife.getPadLotID());
								  }
								  
							  }
							  
		
							  
							  
							  if(sumElapseTime !=null && sumElapseTime!=0){
									  
									  if(totalPadLife >= station.getNextPadLife()){
										  
										  if(station.getNextPadLife() != TaperController.initialNextPadLife){
											  log.info(stationName+" next hour reached.Total Pad Life:"+totalPadLife);
											  processPolynomial(stationName,totalPadLife.intValue(),padLife.getPadLotID());
										  }else{
											  log.info(stationName+" change new pad");
										  }
										  
										  int nextPad = (int)Math.floor(totalPadLife)+1;
										  station.setNextPadLife(nextPad);
										  TaperController.activeStationMap.remove(stationName);
										  TaperController.activeStationMap.put(stationName, station);
										  
									  }
							  }
					  }
			  }
		   }
		
	}
	
	public void processPolynomial(String stationName,int totalPadLife,String padLotId) {
		
		log.info(stationName+" process polynomial.Total Pad Life:"+totalPadLife);
		
		DatabaseManager dm = new DatabaseManager();
		//TaperMap taperMap = dm.getTaperMapByStation(stationName);
		
//		FileOutputStream fileOut;
//		Workbook wb = new HSSFWorkbook();
//		Sheet sheet = wb.createSheet("Export Worksheet");
//		Row row0 = sheet.createRow((short) 0);
//		row0.createCell(0).setCellValue("DC_ELEMENT");
//		row0.createCell(1).setCellValue("LOT_ID");
//		row0.createCell(2).setCellValue("COLLECTION_DATE");
//		row0.createCell(3).setCellValue("WAFER_ID");													
//		row0.createCell(4).setCellValue("CHART_ID");
//		row0.createCell(5).setCellValue("STEP_ID");
//		row0.createCell(6).setCellValue("VALUE");
//		row0.createCell(7).setCellValue("DATA_SOURCE_ID");
//		row0.createCell(8).setCellValue("PRODUCT_ID");
//		row0.createCell(9).setCellValue("VALUE_AVERAGE");
//
//		Row row1;
//		Row row2;

		BigDecimal taperAdjustment;

		try {
			//int i = 1;

			    String leftTaperId = "L"+stationName;
				//process left////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				Polynomial leftPoly = dm.listPolyByArmPadlot(leftTaperId,padLotId);
				//String leftTaperId = "L"+stationName;
				
				//get current taper value
				//TaperValue leftTaper = dm.getTaperValueByTaperId(leftTaperId);
				BigDecimal[] leftCoefficients = {leftPoly.getA0(), leftPoly.getA1(), leftPoly.getA2(), leftPoly.getA3(), leftPoly.getA4(), leftPoly.getA5(), leftPoly.getA6(), leftPoly.getA7(), leftPoly.getA8(), leftPoly.getA9()};
				
				//apply polynomial calculation
				double leftAdjustment = PolyBean.calculatePolynomial(totalPadLife,leftCoefficients).doubleValue();
				log.info(stationName+" process polynomial.Left Adjustment:"+leftAdjustment+" Inches Hg");
				//double micronLeftAdjust = UnitConversion.convertInchesHgToMicrons(leftAdjustment.doubleValue());
				//log.info(stationName+" process polynomial.Left Adjustment:"+leftAdjustment+" (Micron)");
//				row1 = sheet.createRow((short) i);
//				row1.createCell(0).setCellValue(leftPoly.getId().getArmID());
//				
//				row1.createCell(9).setCellValue(UnitConversion.convertInchesHgToMicrons(leftAdjustment.doubleValue()));
				updateDBTaper("L",stationName,leftAdjustment,totalPadLife, padLotId);
				//TaperAdjustProcessor.taperAverageQueue.put(new TaperAverage(taperMap.getLeftTaper(), micronLeftAdjust, ""));
				//i++;
				//Activity.log("ArmID: "+leftTaperId+", Adjustment value:"+micronLeftAdjust+" ", PropertiesLoader.getSystemUser(), "polynomial make adjustment");
				
				
				//process Right //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
				String rightTaperId = "R"+stationName;
				Polynomial rightpoly = dm.listPolyByArmPadlot(rightTaperId,padLotId);
				//
				
				//TaperValue rightTaper = dm.getTaperValueByTaperId(rightTaperId);
				BigDecimal[] rightCoefficients = {rightpoly.getA0(), rightpoly.getA1(), rightpoly.getA2(), rightpoly.getA3(), rightpoly.getA4(), rightpoly.getA5(), rightpoly.getA6(), rightpoly.getA7(), rightpoly.getA8(), rightpoly.getA9()};
				double rightAdjustment = PolyBean.calculatePolynomial(totalPadLife,rightCoefficients).doubleValue();
				log.info(stationName+" process polynomial.Right Adjustment:"+rightAdjustment+" Inches Hg");
				updateDBTaper("R",stationName,rightAdjustment,totalPadLife, padLotId);
				//log.info(stationName+" process polynomial.Right Adjustment:"+rightAdjustment);
				//double micronRightAdjust = UnitConversion.convertInchesHgToMicrons(rightAdjustment.doubleValue());
				//log.info(stationName+" process polynomial.Right Adjustment:"+micronRightAdjust+" (Micron)");
//				row2 = sheet.createRow((short) i);
//				row2.createCell(0).setCellValue(rightpoly.getId().getArmID());
//				
//				row2.createCell(9).setCellValue(UnitConversion.convertInchesHgToMicrons(rightAdjustment.doubleValue()));
				//TaperAdjustProcessor.taperAverageQueue.put(new TaperAverage(taperMap.getRightTaper(), micronRightAdjust, ""));
				//i++;		
				
				//Activity.log("Right ArmID: "+taperMap.getRightTaper()+", Adjustment value:"+micronRightAdjust+" ", PropertiesLoader.getSystemUser(), "polynomial make adjustment");

		} catch (Exception e) {
			List<String> errMsg01 = new ArrayList<String>();
			if (e.getCause() != null)errMsg01.add(e.getCause().toString());
			errMsg01.add(e.toString());
			ErrorMessage.displayError(ErrorMessage.CRITICAL_ERROR, true,
					"ERROR process polynomial", e.getMessage(), errMsg01);
			log.error("PolyPatch:processPolynomial",e);
			
		} 
//		finally {
//			try {
//				fileOut = new FileOutputStream(PropertiesLoader.getTaperAverageOutput());
//				wb.write(fileOut);
//				fileOut.close();
//			} catch (IOException e) {
//				log.error("PolyPatch:processPolynomial",e);
//				ErrorMessage.displayError(ErrorMessage.CRITICAL_ERROR, true,"Error output "+PropertiesLoader.getTaperAverageOutput()+" file", e.getMessage());
//			}
//
//		}
	}
	
	public void updateDBTaper(String arm, String stationName, double taperAdjust,int totalPadLife,String padLotId) {
		String taperID = arm + stationName;
		
		DatabaseManager dm = new DatabaseManager();
		TaperValue taperValue = dm.getTaperValueByTaperId(taperID);

			if (taperAdjust > PropertiesLoader.getVacuumUpperLimit()) {
				//String message = "Upper limit exceeded "+PropertiesLoader.getVacuumUpperLimit()+" : WCS adjusting " + taperID + " from value " + taperAdjust+ " adjust to " + PropertiesLoader.getVacuumUpperLimit();
				String message = "Upper limit exceeded : Adjust" + taperID + " from value " + taperAdjust + " to maksimum " + PropertiesLoader.getVacuumUpperLimit()+"Hg";
				//String malayMessage = "Melebehi tahap maksimum "+PropertiesLoader.getVacuumUpperLimit()+": WCS adjust " + taperID +" dari " +taperAdjust +" tukar ke "+PropertiesLoader.getVacuumUpperLimit();
				String malayMessage = "Melebehi vacuum maksimum : Adjust " + taperID +" dari " +taperAdjust +" tukar kepada vacuum maksimum "+PropertiesLoader.getVacuumUpperLimit()+"Hg";
				Activity.log(message, PropertiesLoader.getSystemUser(), "Polynomial adjustment had been limited to upper value "+PropertiesLoader.getVacuumUpperLimit());
				log.info("Taper value:"+taperAdjust+" exceed limit:"+PropertiesLoader.getVacuumUpperLimit());
				taperAdjust = PropertiesLoader.getVacuumUpperLimit();
				
				List<String> errMsg01 = new ArrayList<String>();
				errMsg01.add(message);
				errMsg01.add(malayMessage);
                ErrorMessage.displayError(ErrorMessage.WARNING_ERROR, true, "POlynomial vacuum adjustment - Upper Limit", "Taper Adjust ", errMsg01);
			}

			if (taperAdjust < PropertiesLoader.getVacuumLowerLimit()) {
				String message = "Lower limit exceeded : Adjust" + taperID + " from value " + taperAdjust + " to minimum " + PropertiesLoader.getVacuumLowerLimit()+"Hg";

				String malayMessage = "Melebehi vacuum minima : Adjust " + taperID +" dari " +taperAdjust +" tukar kepada vacuum minima "+PropertiesLoader.getVacuumLowerLimit()+"Hg";

				Activity.log(message, PropertiesLoader.getSystemUser(), "Polynomial adjustment had been limited to lower value "+PropertiesLoader.getVacuumLowerLimit() + " by SYSTEM");
				log.info("Taper value:"+taperAdjust+" lower then limit:"+PropertiesLoader.getVacuumLowerLimit());
				taperAdjust = PropertiesLoader.getVacuumLowerLimit();

				List<String> errMsg01 = new ArrayList<String>();
				errMsg01.add(message);
				errMsg01.add(malayMessage);
                ErrorMessage.displayError(ErrorMessage.WARNING_ERROR, true, "POlynomial vacuum adjustment - Lower Limit", "Taper Adjust ", errMsg01);
				
			}

			
			taperValue.setAdjustmentValue(taperAdjust);
			EntityWrapper<TaperValue> db = new EntityWrapper<TaperValue>();
			db.merge(taperValue);
			db.commit();
			
			
			EntityWrapper<PolyResult> db2 = new EntityWrapper<PolyResult>();
			PolyResult polyResult = new PolyResult();
			PolyResultPK polyResultPK = new PolyResultPK();
			polyResultPK.setArm(arm);
			polyResultPK.setPadlife(totalPadLife);
			polyResultPK.setPadlotid(padLotId);
			polyResultPK.setStation(stationName);
			polyResult.setId(polyResultPK);
			polyResult.setTapervalue(taperAdjust);
			
			db2.merge(polyResult);
			db2.commit();
			
			EntityWrapper<Polyfull> db3 = new EntityWrapper<Polyfull>();
			Polyfull polyFull = new Polyfull();
			polyFull.setArm(arm);
			polyFull.setDate(new Date ());
			polyFull.setPadlife(totalPadLife);
			polyFull.setPadlotid(padLotId);
			polyFull.setStation(stationName);
			polyFull.setTapervalue(taperAdjust);
			
			db3.add(polyFull);
			db3.commit();
			
			// Logging.log(new Date(), "Update Vacuum:" + stationName + "[" +
			// arm + "]-LOTID=" + lotID + ",average=" + averageValue +
			// " Adjust " + value + "=" + taperValueDouble, "SYSTEM",
			// "Data auto received from WCS");
			//Activity.log("Update Vacuum:" + stationName + "[" + arm + "]-LOTID=" + lotID + ",Current Taper value=" + oriTaperValueDouble+" Adjust " + value + "=" + taperValueDouble, PropertiesLoader.getSystemUser(), "Data auto received from WCS");
			Activity.log("ArmID: "+taperID+", Adjustment value:"+taperAdjust+" ", PropertiesLoader.getSystemUser(), "polynomial make adjustment");
			log.info("Polynomial adjust armID:" + taperID + " with value: " + taperAdjust);
			PLCSend.updatePLCTaper(arm, stationName, taperAdjust);
		//}

	}
	
}